package com.shop.cereshop.admin.service.config.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.shop.cereshop.admin.dao.config.CereConfigDAO;
import com.shop.cereshop.admin.param.config.ConfigIdParam;
import com.shop.cereshop.admin.param.config.ConfigQueryParam;
import com.shop.cereshop.admin.param.config.ConfigSaveParam;
import com.shop.cereshop.admin.param.config.ConfigUpdateParam;
import com.shop.cereshop.admin.redis.service.api.StringRedisService;
import com.shop.cereshop.admin.service.config.CereConfigService;
import com.shop.cereshop.commons.constant.ConfigConstants;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.domain.common.Page;
import com.shop.cereshop.commons.domain.config.CereConfig;
import com.shop.cereshop.commons.domain.user.CerePlatformUser;
import com.shop.cereshop.commons.exception.CoBusinessException;
import com.shop.cereshop.commons.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
@Slf4j(topic = "CereConfigServiceImpl")
public class CereConfigServiceImpl implements CereConfigService {

    @Autowired
    private CereConfigDAO cereConfigDAO;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private StringRedisService stringRedisService;

    @Override
    public void save(ConfigSaveParam param, CerePlatformUser user) throws CoBusinessException {
        ensureKeyUnique(param.getConfigKey(), null);
        CereConfig entity = new CereConfig();
        BeanUtils.copyProperties(param, entity);
        String now = TimeUtils.yyMMddHHmmss();
        entity.setCreateBy(user != null ? user.getUsername() : null);
        entity.setUpdateBy(entity.getCreateBy());
        entity.setCreateTime(LocalDateTime.parse(now, TimeUtils.DATE_TIME_FORMATTER));
        entity.setUpdateTime(entity.getCreateTime());
        cereConfigDAO.insert(entity);
        refreshConfigCache();
    }

    @Override
    public void update(ConfigUpdateParam param, CerePlatformUser user) throws CoBusinessException {
        CereConfig db = cereConfigDAO.selectById(param.getConfigId());
        if (db == null) {
            throw new CoBusinessException(CoReturnFormat.LOGIC_ERROR_DATABASE);
        }
        ensureKeyUnique(param.getConfigKey(), param.getConfigId());
        CereConfig entity = new CereConfig();
        BeanUtils.copyProperties(param, entity);
        String now = TimeUtils.yyMMddHHmmss();
        entity.setUpdateBy(user != null ? user.getUsername() : null);
        entity.setUpdateTime(LocalDateTime.parse(now, TimeUtils.DATE_TIME_FORMATTER));
        cereConfigDAO.updateById(entity);
        refreshConfigCache();
    }

    @Override
    public void delete(ConfigIdParam param, CerePlatformUser user) throws CoBusinessException {
        cereConfigDAO.deleteById(param.getConfigId());
        refreshConfigCache();
    }

    @Override
    public Page<CereConfig> getAll(ConfigQueryParam param) throws CoBusinessException {
        PageHelper.startPage(param.getPage(), param.getPageSize());
        LambdaQueryWrapper<CereConfig> wrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(param.getConfigName())) {
            wrapper.like(CereConfig::getConfigName, param.getConfigName());
        }
        if (StringUtils.isNotBlank(param.getConfigKey())) {
            wrapper.like(CereConfig::getConfigKey, param.getConfigKey());
        }
        if (StringUtils.isNotBlank(param.getConfigType())) {
            wrapper.eq(CereConfig::getConfigType, param.getConfigType());
        }
        wrapper.orderByDesc(CereConfig::getUpdateTime);
        List<CereConfig> list = cereConfigDAO.selectList(wrapper);
        PageInfo<CereConfig> pageInfo = new PageInfo<>(list);
        return new Page<>(pageInfo.getList(), pageInfo.getTotal());
    }

    @Override
    public CereConfig getById(Integer configId) throws CoBusinessException {
        return cereConfigDAO.selectById(configId);
    }

    /**
     * 启动时加载配置到 Redis
     */
    public void loadAllToRedis() {
        log.info("加载系统参数配置到Redis");
        List<CereConfig> configs = cereConfigDAO.selectList(Wrappers.emptyWrapper());
        HashOperations<String, String, String> ops = stringRedisTemplate.opsForHash();
        stringRedisTemplate.delete(ConfigConstants.SYS_CONFIG_CACHE_KEY);
        for (CereConfig config : configs) {
            if (StringUtils.isNotBlank(config.getConfigKey())) {
                ops.put(ConfigConstants.SYS_CONFIG_CACHE_KEY, config.getConfigKey(),
                        config.getConfigValue() == null ? "" : config.getConfigValue());
            }
        }
    }

    private void refreshConfigCache() {
        try {
            loadAllToRedis();
        } catch (Exception e) {
            log.error("刷新系统参数缓存失败", e);
        }
    }

    private void ensureKeyUnique(String configKey, Integer excludeId) throws CoBusinessException {
        if (StringUtils.isBlank(configKey)) {
            return;
        }
        LambdaQueryWrapper<CereConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CereConfig::getConfigKey, configKey);
        if (excludeId != null) {
            wrapper.ne(CereConfig::getConfigId, excludeId);
        }
        Integer count = cereConfigDAO.selectCount(wrapper);
        if (count != null && count > 0) {
            throw new CoBusinessException(CoReturnFormat.UNIQUE_ERROR);
        }
    }
}


